package AudioServer;

import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.net.telnet.TelnetClient;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import interactivespaces.activity.impl.web.BaseRoutableRosWebServerActivity;

/**
 * A simple Interactive Spaces Java-based activity.
 */
public class AudioServer extends BaseRoutableRosWebServerActivity {

	private List<String> audioSources;
	private List<String> audioSystems;
	
	private List<String> stations;
	
	Map<String, TelnetHandler> telnetHandlers;
	
	@Override
	public void onWebSocketReceive(String connectionId, Object message) {
		getLog().info("Got message:" + message.toString());
		Map<String, Object> data = (Map<String, Object>)message;
		if (data.containsKey("request") && data.get("request").equals("systemInfo")) {
			Map<String, Object> response = Maps.newHashMap();
			Map<String, Object> systemData = Maps.newHashMap();
			systemData.put("soundSystems", audioSystems);
			systemData.put("soundSources", audioSources);
			response.put("system_info", systemData);
			sendWebSocketJson(connectionId, response);
		} else if (data.containsKey("request") && data.get("request").equals("pandoraStations")) {
			Map<String, Object> response = Maps.newHashMap();
			response.put("pandora_stations", stations);
			String system = (String)data.get("soundSystem");
			sendWebSocketJson(connectionId, response);			
			sendTelnetCommand(system, "stations");
		} else if (data.containsKey("request") && data.get("request").equals("pause")) {
			String system = (String)data.get("soundSystem");
			pauseSystem(system);
		} else if (data.containsKey("request") && data.get("request").equals("playSource")) {
			String system = (String)data.get("soundSystem");
			getLog().info("playing " + system);
			if (data.containsKey("audioSource")) {
				pauseSystem(system);
				String source = (String)data.get("audioSource");
				playSource(system, source);
			}
			else if (data.containsKey("pandoraStation")) {
				pauseSystem(system);
				String pandoraStation = (String)data.get("pandoraStation");
				playPandora(system, pandoraStation);
			}
		}
	}
	
    private void playPandora(String system, String pandoraStation) {
    	sendTelnetCommand(system, "play STATION \"" + pandoraStation + "\"");
	}

    private synchronized void sendTelnetCommand(String system, String command) {
    	String systemHost = getConfiguration().getRequiredPropertyString("space.activity.systems." + system);
    	int pandoraPort = getConfiguration().getPropertyInteger("space.activity.systems.pandoraPort." + system, 4445);
    	
    	if (!telnetHandlers.containsKey(system)) {
    		telnetHandlers.put(system, new TelnetHandler(system, systemHost, pandoraPort, getLog(), new MessageHandler() {
    			@Override
    			public void handleMessage(String name, String message) {
    				parseTelnetResponse(name, message);
    			}
    		}));
    		getManagedCommands().submit(telnetHandlers.get(system));
    	}
    	telnetHandlers.get(system).sendCommand(command);
    }
    
    private synchronized void parseTelnetResponse(String name, String message) {
    	getLog().info("Got telnet response from " + name);
    	getLog().info(message);
    	List<String> lines = Arrays.asList(message.split("\n"));
    	for (String line : lines) {
    		if (line.startsWith("115")) {
    			int stationStart = line.indexOf(":") + 2;
    			String station = line.substring(stationStart);
    			if (!stations.contains(station)) {
    				stations.add(station);
    			}
    		}
    	}
    }
    
	private synchronized void playSource(String system, String source) {
    	String sourceUrl = getConfiguration().getRequiredPropertyString("space.activity.sources." + source);
    	String systemHost = getConfiguration().getRequiredPropertyString("space.activity.systems." + system);
    	String vlcPort = getConfiguration().getRequiredPropertyString("space.activity.systems.vlcPort." + system);
    	String url = buildPlayUrl(systemHost + ":" + vlcPort, sourceUrl);
    	executeUrl(url);
	}

	private void executeUrl(String url) {
		getLog().info("Executing url " + url);
		URL toExecute;
		try {
			toExecute = new URL(url);
		} catch (MalformedURLException e) {
			getLog().warn("Malformed execute url");
			getLog().warn(e.toString());
			return;
		}
		try {
			toExecute.openStream();
		} catch (IOException e) {
			getLog().warn("Could not open url");
			getLog().warn(e.toString());
		}
	}

	private String buildPlayUrl(String systemUrl, String sourceUrl) {
		return "http://" + systemUrl + "/requests/status.xml?command=in_play&input=" + sourceUrl;
	}

	private void pauseSystem(String system) {
		stopPandora(system);
		stopAudioSource(system);
	}

	private synchronized void stopAudioSource(String system) {
		String systemUrl = getConfiguration().getRequiredPropertyString("space.activity.systems." + system);
		String url = buildStopUrl(systemUrl);
		executeUrl(url);
	}

	private String buildStopUrl(String systemUrl) {
		return "http://" + systemUrl + "/requests/status.xml?command=pl_stop";
	}

	private void stopPandora(String system) {
		sendTelnetCommand(system, "STOP NOW");
	}

	private List<String> getPandoraStations(String system) {
		sendTelnetCommand(system, "stations");
		return stations;
	}

	@Override
    public void onActivitySetup() {
        getLog().info("Activity AudioServer setup");
    }

	@Override
	public void onActivityStartup() {
		getLog().info("Activity AudioServer startup");
		telnetHandlers = Maps.newHashMap();
		String systemString = getConfiguration().getPropertyString("space.activity.soundSystems");
		String sourceString = getConfiguration().getPropertyString("space.activity.soundSources");
		audioSources = Arrays.asList(sourceString.split(":"));
		audioSystems = Arrays.asList(systemString.split(":"));
		stations = Lists.newArrayList();
		if (audioSystems.size() > 0) {
			sendTelnetCommand(audioSystems.get(0), "stations");
		}
	}

	@Override
	public void onActivityActivate() {
		getLog().info("Activity AudioServer activate");
	}

	@Override
	public void onActivityDeactivate() {
		getLog().info("Activity AudioServer deactivate");
	}

	@Override
	public void onActivityShutdown() {
		getLog().info("Activity AudioServer shutdown");
	}

    @Override
    public void onActivityCleanup() {
        getLog().info("Activity AudioServer cleanup");
    }
}
